package net.fornwall.eclipsecoder.rubysupport;

import java.lang.reflect.Array;
import java.util.List;

import net.fornwall.eclipsecoder.stats.CodeGenerator;
import net.fornwall.eclipsecoder.stats.ProblemStatement;

public class RubyCodeGenerator extends CodeGenerator {

    public RubyCodeGenerator(ProblemStatement problemStatement) {
        super(problemStatement);

        // cannot have capitalized parameter name in ruby
        List<String> parameterNames = problemStatement.getParameterNames();
        for (int i = 0; i < parameterNames.size(); i++) {
            parameterNames.set(i, parameterNames.get(i).substring(0, 1).toLowerCase()
                    + parameterNames.get(i).substring(1));
        }
    }

    private String getCreateStatement(Object value, String variableName) {
        return variableName + " = " + getValueString(value) + "\n";
    }

    @Override
    public String getDummyReturnString() {
        return "nil";
    }

    @Override
    protected String getMethodParamsString() {
        StringBuilder builder = new StringBuilder();
        for (String name : problemStatement.getParameterNames()) {
            if (builder.length() != 0)
                builder.append(", ");
            builder.append(name);
        }
        return builder.toString();
    }

    @Override
    public String getTestsSource() {
        StringBuilder builder = new StringBuilder("require 'test/unit'\nrequire '"
                + problemStatement.getSolutionClassName() + "'\n\nclass "
                + problemStatement.getSolutionClassName() + "Test < Test::Unit::TestCase\n"
                + "\tdef setup\n\t\t@solution = " + problemStatement.getSolutionClassName()
                + ".new\n\tend\n\n");
        int count = 0;

        for (ProblemStatement.TestCase testCase : problemStatement.getTestCases()) {
            // pad with zero as the Test::Unit view uses lexical ordering of tests
            builder.append("\tdef test_" + (count < 10 ? "0" : "") + count + "\n");

            for (int i = 0; i < testCase.getParameters().length; i++) {
                builder.append("\t\t");
                builder.append(getCreateStatement(testCase.getParameters()[i], problemStatement
                        .getParameterNames().get(i)));
            }

            builder.append("\n\t\t");
            builder.append(getCreateStatement(testCase.returnValue, "expected"));
            builder.append("\t\t");
            builder.append("actual = @solution." + problemStatement.getSolutionMethodName() + "("
                    + getMethodParamsString() + ")");

            // TODO: Use special equal for double..
            builder.append("\n\t\tassert_equal(expected, actual)\n");
            builder.append("\tend\n\n");
            count++;
        }

        builder.append("end");
        return builder.toString();
    }

    @Override
    public String getTypeString(Class<?> type) {
        return "";
    }

    private String getValueString(Object value) {
        Class<?> type = value.getClass();
        if (type == Integer.class || type == Long.class || type == Double.class) {
            return value.toString();
        } else if (type == String.class) {
            return "'" + value.toString() + "'";
        } else if (type.isArray()) {
            StringBuilder builder = new StringBuilder("[");
            for (int i = 0; i < Array.getLength(value); i++) {
                if (i != 0)
                    builder.append(", ");
                builder.append(getValueString(Array.get(value, i)));
            }
            builder.append("]");
            return builder.toString();
        } else {
            throw new IllegalArgumentException("Got type \"" + type + "\"");
        }
    }

}
